package com.ltcode.auth.domain.model;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 验证码领域模型
 * 
 * @author ltcode
 * @since 2024-01-01
 */
@Data
public class Captcha implements Serializable {
    
    private static final long serialVersionUID = 1L;

    /** 验证码唯一标识 */
    private String uuid;

    /** 验证码内容 */
    private String code;

    /** 验证码图片（Base64编码） */
    private String image;

    /** 验证码类型 */
    private CaptchaType type;

    /** 创建时间 */
    private Date createTime;

    /** 过期时间 */
    private Date expireTime;

    /** 是否已使用 */
    private boolean used;

    /** 验证失败次数 */
    private int failCount;

    /** 最大验证失败次数 */
    private static final int MAX_FAIL_COUNT = 3;

    /**
     * 验证码类型枚举
     */
    public enum CaptchaType {
        CHAR("char", "字符验证码"),
        MATH("math", "数学运算验证码"),
        SLIDE("slide", "滑动验证码"),
        CLICK("click", "点击验证码");

        private final String code;
        private final String description;

        CaptchaType(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 检查验证码是否有效
     */
    public boolean isValid() {
        return !used && !isExpired() && failCount < MAX_FAIL_COUNT;
    }

    /**
     * 检查验证码是否过期
     */
    public boolean isExpired() {
        return expireTime != null && expireTime.before(new Date());
    }

    /**
     * 验证验证码
     */
    public boolean validate(String inputCode) {
        if (!isValid()) {
            return false;
        }

        boolean isCorrect = code.equalsIgnoreCase(inputCode);
        
        if (isCorrect) {
            this.used = true;
        } else {
            this.failCount++;
        }

        return isCorrect;
    }

    /**
     * 标记为已使用
     */
    public void markAsUsed() {
        this.used = true;
    }

    /**
     * 增加失败次数
     */
    public void incrementFailCount() {
        this.failCount++;
    }

    /**
     * 检查是否达到最大失败次数
     */
    public boolean isMaxFailCountReached() {
        return failCount >= MAX_FAIL_COUNT;
    }

    /**
     * 创建字符验证码
     */
    public static Captcha createCharCaptcha(String uuid, String code, String image, int expireMinutes) {
        Captcha captcha = new Captcha();
        captcha.setUuid(uuid);
        captcha.setCode(code);
        captcha.setImage(image);
        captcha.setType(CaptchaType.CHAR);
        captcha.setCreateTime(new Date());
        captcha.setExpireTime(new Date(System.currentTimeMillis() + expireMinutes * 60 * 1000));
        captcha.setUsed(false);
        captcha.setFailCount(0);
        return captcha;
    }

    /**
     * 创建数学运算验证码
     */
    public static Captcha createMathCaptcha(String uuid, String code, String image, int expireMinutes) {
        Captcha captcha = new Captcha();
        captcha.setUuid(uuid);
        captcha.setCode(code);
        captcha.setImage(image);
        captcha.setType(CaptchaType.MATH);
        captcha.setCreateTime(new Date());
        captcha.setExpireTime(new Date(System.currentTimeMillis() + expireMinutes * 60 * 1000));
        captcha.setUsed(false);
        captcha.setFailCount(0);
        return captcha;
    }

    /**
     * 获取验证码结果（用于返回给前端）
     */
    public CaptchaResult toResult() {
        CaptchaResult result = new CaptchaResult();
        result.setUuid(this.uuid);
        result.setImage(this.image);
        result.setType(this.type.getCode());
        return result;
    }

    /**
     * 验证码结果类
     */
    @Data
    public static class CaptchaResult implements Serializable {
        private static final long serialVersionUID = 1L;
        
        /** 验证码唯一标识 */
        private String uuid;
        
        /** 验证码图片（Base64编码） */
        private String image;
        
        /** 验证码类型 */
        private String type;
        
        /** 是否启用验证码 */
        private boolean enabled = true;
    }
}
